package org.safs.tools;
import java.io.File;
import java.io.FileFilter;
import java.io.FilenameFilter;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URL;
//import org.safs.Log;
/**
* This Class is meant to extend File behavior allowing for
* case insensitive files. This "has a" internal protected File object
* and all File methods are implemented by simplying returning the internal
* File.method() for all File methods. The toFile() method returns the
* internal File object.
* <p>
* This class has no SAFS dependencies and can be packaged independent of other SAFS classes.
*
* @author Jack Imbriani
*/
public class CaseInsensitiveFile {
// internal File used to surface File behavior
protected File ciFile = null ;
/**
* @see java.io.File#File(java.lang.String)
*/
public CaseInsensitiveFile(String pathname) {
ciFile = getCaseInsensitiveFile(pathname);
}
/**
* @see java.io.File#File(java.lang.String, java.lang.String)
*/
public CaseInsensitiveFile(String parent, String child) {
ciFile = getCaseInsensitiveFile(parent + File.separator + child);
}
/**
* @see java.io.File#File(java.io.File, java.lang.String)
*/
public CaseInsensitiveFile(File parent, String child) {
ciFile = getCaseInsensitiveFile(parent.getPath() + File.separator + child);
}
/**
* @see java.io.File#File(java.io.File, java.lang.String)
*/
public CaseInsensitiveFile(CaseInsensitiveFile parent, String child) {
ciFile = getCaseInsensitiveFile(parent.getPath() + File.separator + child);
}
/**
* @see java.io.File#File(java.net.URI)
* Note that case insensitivity does not apply to URI
*/
public CaseInsensitiveFile(URI uri) {
// case insensetivity does not apply here.
ciFile = new File(uri) ;
}
/**
* Method toFile.
* @return File Returns the internal File object so can be used as a File
*/
public File toFile() {
return ciFile ;
}
/*
******************************************************************************
*
* handle directory path search beginning with root and returning first matching
*
******************************************************************************
*/
protected File getCaseInsensitiveFile( String strFile ) {
// early return possibility if strFile exists exactly as is
File theFile = new File(strFile) ;
if( theFile.exists() ) return theFile ;
//remove any enclosing quotes
try{
if(strFile.charAt(0)==(char)34) strFile = strFile.substring(1);
if(strFile.charAt(strFile.length()-1)==(char)34) strFile = strFile.substring(0, strFile.length()-1);
}catch(Exception x){
//Log.debug("CaseInsensitiveFile.getCaseInsensitiveFile for '"+ strFile +"' IGNORING: "+ x.getClass().getSimpleName());
}
// we need to work with whatever file.separator the System is using noting that
// windows uses \ as a separator requiring the String.split regexp to use \\
String file_separator = File.separator ;
if( file_separator.equals("\\") ) file_separator += "\\" ;
// work with array of strings that make up the strFile path
String subpaths[] = strFile.split(file_separator) ;
// the case insensitive file object
File caseInsensitiveFile = null ;
// traverse the subpaths building foundPath as we go using the strFile
// substrings exactly if they make an existing path, or case permuted variants
// of the substrings if found
// this will store the path to the file we find including variants of case
// note that only the first case permuted variant will be used if multiple exist
String foundPath = "" ;
// absolute and relative files behave differently and considerations must be made
// for how they are specified (begin with File.separator, filesystemroot, or .)
int start_idx = 0 ;
if( theFile.isAbsolute() ) {
// may begin with File.separator or drive specification (c:\ for example)
if( theFile.getPath().startsWith(file_separator) ) {
// starting with file_separator means [i.e. /file (unix) or \file (windows)]
start_idx = 1 ;
} else {
// subpaths[0] should be file root specification (c: on windows for example)
foundPath = subpaths[0] ;
start_idx = 1 ;
}
} else {
// relative path may begin with . or a name.
// a name requires prepending ., finding name, then removing .+file_separator
// if begins with ., treat like absolute path (no else needed)
if( ! subpaths[0].startsWith(".") ) {
File relFile = findFileMP(".",subpaths[0]) ;
// return early using original strFile if no match found
if( relFile == null ) return new File(strFile) ;
foundPath = relFile.getPath().replaceFirst("."+file_separator,"") ;
start_idx = 1 ;
}
}
// traverse the subpaths building foundPath as we go using the strFile
// substrings exactly if they make an existing path, or case permuted variants
// of the substrings if found
for( int idx = start_idx ; idx < subpaths.length ; idx++ ) {
String huntPath = null ;
if( ! foundPath.equals("") ) {
// foundPath has been set, either above or in prior iteration, so go with it
huntPath = foundPath + File.separator + subpaths[idx] ;
} else {
// empty foundPath means have to set huntPath
// and possibly foundPath prior to use
if( theFile.isAbsolute() ) {
// absolute file, start with separator and hunt for subpaths[idx]
foundPath = File.separator ;
huntPath = subpaths[idx] ;
} else {
// relative file, use subpaths[idx] as starting point
// foundPath is set above
huntPath = subpaths[idx] ;
}
}
File tfile = new File(huntPath) ;
if( tfile.exists() ) {
// path exists as is, so use it exactly
foundPath = tfile.getPath() ;
} else {
// path does not exist as is, so search for case permuted variants
// we know that foundPath exists so use helper method for
// case insensitive compares taking the first match found
caseInsensitiveFile = findFileMP(foundPath,subpaths[idx]) ;
if( caseInsensitiveFile != null ) {
// variant found, use it in the foundPath
foundPath = caseInsensitiveFile.getPath() ;
} else {
// no case permuted variant exists.
// return File based on current foundPath and
// remaining portion of original input strFile path
String therest = "" ;
for ( int i = idx ; i < subpaths.length ; i++ ) {
therest += File.separator + subpaths[i] ;
}
return new File(foundPath+therest) ;
}
}
}
// return a File which will be some permutation of strFile
// not sure why but need to create new File object instead
// of returning caseInsensitiveFile. guess is object goes out of scope.
return new File(foundPath) ;
}
// this method was copied from Carl's work in org.safs.tools.input.UniqueStringFileInfo
// find a case-insensitive match to the provided filename.ext
// rootpath is expected to be a valid/verified path on the current platform.
// we will search all files in the rootpath directory looking for a case-insensitive
// match. This is needed to support Unix case-sensitive filenames.
protected File findFileMP(String rootpath, String afilename){
File fdir = new File(rootpath);
if (!fdir.isDirectory()) return null;
String[] files = fdir.list();
if ((files == null)||(files.length == 0)) return null;
String lcfile;
String lcfilename = afilename.toLowerCase();
for (int i=0; i< files.length; i++){
lcfile = files[i].toLowerCase();
if (lcfile.equals(lcfilename)) return new File(fdir, files[i]);
}
return null;
}
/*
******************************************************************************
*
* All of the following methods simply invoke and return
* ciFile.method(args). These are all methods of the File object
* and this design was chosen because we cannot extend File and manipulate
* args before calling the super constructors. These methods let the
* CaseInsensitiveFile behave like a File without being a File.
*
******************************************************************************
*/
/**
* @see java.io.File#canRead()
*/
public boolean canRead() {
return ciFile.canRead();
}
/**
* @see java.io.File#canWrite()
*/
public boolean canWrite() {
return ciFile.canWrite();
}
/**
* @see java.io.File#compareTo(java.io.File)
*/
public int compareTo(File arg0) {
return ciFile.compareTo(arg0);
}
/**
* @see java.lang.Comparable#compareTo(java.lang.Object)
*/
public int compareTo(Object arg0) {
return ciFile.compareTo((File)arg0);
}
/**
* @see java.io.File#createNewFile()
*/
public boolean createNewFile() throws IOException {
return ciFile.createNewFile();
}
/**
* @see java.io.File#delete()
*/
public boolean delete() {
return ciFile.delete();
}
/**
* @see java.io.File#deleteOnExit()
*/
public void deleteOnExit() {
ciFile.deleteOnExit();
}
/**
* @see java.lang.Object#equals(java.lang.Object)
*/
public boolean equals(Object arg0) {
return ciFile.equals(arg0);
}
/**
* @see java.io.File#exists()
*/
public boolean exists() {
return ciFile.exists();
}
/**
* @see java.io.File#getAbsoluteFile()
*/
public File getAbsoluteFile() {
return ciFile.getAbsoluteFile();
}
/**
* @see java.io.File#getAbsolutePath()
*/
public String getAbsolutePath() {
return ciFile.getAbsolutePath();
}
/**
* @see java.io.File#getCanonicalFile()
*/
public File getCanonicalFile() throws IOException {
return ciFile.getCanonicalFile();
}
/**
* @see java.io.File#getCanonicalPath()
*/
public String getCanonicalPath() throws IOException {
return ciFile.getCanonicalPath();
}
/**
* @see java.io.File#getName()
*/
public String getName() {
return ciFile.getName();
}
/**
* @see java.io.File#getParent()
*/
public String getParent() {
return ciFile.getParent();
}
/**
* @see java.io.File#getParentFile()
*/
public File getParentFile() {
return ciFile.getParentFile();
}
/**
* @see java.io.File#getPath()
*/
public String getPath() {
return ciFile.getPath();
}
/**
* @see java.lang.Object#hashCode()
*/
public int hashCode() {
return ciFile.hashCode();
}
/**
* @see java.io.File#isAbsolute()
*/
public boolean isAbsolute() {
return ciFile.isAbsolute();
}
/**
* @see java.io.File#isDirectory()
*/
public boolean isDirectory() {
return ciFile.isDirectory();
}
/**
* @see java.io.File#isFile()
*/
public boolean isFile() {
return ciFile.isFile();
}
/**
* @see java.io.File#isHidden()
*/
public boolean isHidden() {
return ciFile.isHidden();
}
/**
* @see java.io.File#lastModified()
*/
public long lastModified() {
return ciFile.lastModified();
}
/**
* @see java.io.File#length()
*/
public long length() {
return ciFile.length();
}
/**
* @see java.io.File#list()
*/
public String[] list() {
return ciFile.list();
}
/**
* @see java.io.File#list(java.io.FilenameFilter)
*/
public String[] list(FilenameFilter arg0) {
return ciFile.list(arg0);
}
/**
* @see java.io.File#listFiles()
*/
public File[] listFiles() {
return ciFile.listFiles();
}
/**
* @see java.io.File#listFiles(java.io.FileFilter)
*/
public File[] listFiles(FileFilter arg0) {
return ciFile.listFiles(arg0);
}
/**
* @see java.io.File#listFiles(java.io.FilenameFilter)
*/
public File[] listFiles(FilenameFilter arg0) {
return ciFile.listFiles(arg0);
}
/**
* @see java.io.File#mkdir()
*/
public boolean mkdir() {
return ciFile.mkdir();
}
/**
* @see java.io.File#mkdirs()
*/
public boolean mkdirs() {
return ciFile.mkdirs();
}
/**
* @see java.io.File#renameTo(java.io.File)
*/
public boolean renameTo(File arg0) {
return ciFile.renameTo(arg0);
}
/**
* @see java.io.File#setLastModified(long)
*/
public boolean setLastModified(long arg0) {
return ciFile.setLastModified(arg0);
}
/**
* @see java.io.File#setReadOnly()
*/
public boolean setReadOnly() {
return ciFile.setReadOnly();
}
/**
* @see java.lang.Object#toString()
*/
public String toString() {
return ciFile.toString();
}
/**
* @see java.io.File#toURI()
*/
public URI toURI() {
return ciFile.toURI();
}
/**
* @see java.io.File#toURL()
*/
public URL toURL() throws MalformedURLException {
return ciFile.toURL();
}
}